home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 21 / Cream of the Crop 21 (Terry Blount) (October 1996).iso / doom / quake.zip / QUDPROXY.ZIP / QUDPROXY.GZ / QUDPROXY / qudproxy.c < prev    next >
C/C++ Source or Header  |  1996-07-10  |  7KB  |  264 lines

  1. /* Quake UDP proxy
  2.    Original ipx->udp proxy by tz@execpc.com
  3.    Adapted for udp->udp, other changes by jason@cygnus.com
  4.  
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 2, or (at your option)
  8.    any later version.
  9.  
  10.    compile with "gcc -O2 -o qudproxy qudproxy.c"
  11.    version 1.0
  12.    todo: translate broadcasts, server list
  13.  
  14.    Note: This program properly handles proxying for multiple clients, but
  15.    as of Quake 0.92 the quake server only allows one client from each IP
  16.    address, so only one player can use the proxy at a time; if another
  17.    player connects to the proxy, the remote server will disconnect the
  18.    first player.  I've complained about this to id.
  19. */
  20.  
  21. #include <sys/types.h>
  22. #include <netinet/in.h>
  23. #include <sys/ioctl.h>
  24. #include <sys/socket.h>
  25. #include <sys/time.h>
  26. #include <arpa/inet.h>
  27. #include <netdb.h>
  28. #include <sys/wait.h>
  29.  
  30. #include <stdio.h>
  31. #include <unistd.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34.  
  35. extern char *optarg;
  36. extern int optind;
  37.  
  38. #define VERSION "1.0"
  39.  
  40. #define MAX 4096
  41. unsigned char       msg[MAX];
  42. char *name;
  43.  
  44. void usage ()
  45. {
  46.   fprintf (stderr, "usage: %s [-l localport] [-r remoteport]", name);
  47.   fprintf (stderr, " [-d[d]] [-h] server\n");
  48. }
  49.  
  50. int                 main (int argc, char *argv[])
  51. {
  52.   int sfd, cfd, c2fd, n, ucl, i, pid, opt;
  53.   fd_set fds;
  54.   struct sockaddr_in cremote_addr, clocal_addr;
  55.   struct sockaddr_in sremote_addr, slocal_addr;
  56.   struct hostent *host;
  57.   struct timeval tv, *tvp;
  58.   int localport = 26000, remoteport = 26000, debug = 0;
  59.  
  60.   name = argv[0];
  61.  
  62.   while (opt = getopt (argc, argv, "l:r:dhv"), opt != -1)
  63.     {
  64.       switch (opt)
  65.     {
  66.     case 'l':
  67.       localport = atoi (optarg);
  68.       break;
  69.  
  70.     case 'r':
  71.       remoteport = atoi (optarg);
  72.       break;
  73.  
  74.     case 'd':
  75.       ++debug;
  76.       break;
  77.  
  78.     case 'v':
  79.       fprintf (stderr, "qudproxy version %s", VERSION);
  80.       return 0;
  81.  
  82.     default:
  83.       usage ();
  84.       return opt != 'h';
  85.     }
  86.     }
  87.  
  88.   if (optind != argc - 1)
  89.     {
  90.       usage ();
  91.       return 1;
  92.     }
  93.  
  94.   ucl = sizeof (struct sockaddr_in);
  95.  
  96.   bzero (&sremote_addr, ucl);
  97.   sremote_addr.sin_family = AF_INET;
  98.   sremote_addr.sin_port = htons (remoteport);
  99.   n = inet_addr (argv[optind]);
  100.   if (n != -1)
  101.     memcpy (&sremote_addr.sin_addr, &n, sizeof(n));
  102.   else
  103.     {
  104.       host = gethostbyname (argv[optind]);
  105.       if (host == NULL)
  106.     return (-1);
  107.       memcpy (&sremote_addr.sin_addr, host->h_addr, host->h_length);
  108.     }
  109.  
  110.   bzero (&clocal_addr, ucl);
  111.   clocal_addr.sin_family = AF_INET;
  112.   clocal_addr.sin_port = htons (localport);
  113.  
  114.   /* Surely there's a better way to determine our IP address.  */
  115.   gethostname (msg, MAX);
  116.   host = gethostbyname (msg);
  117.   memcpy (&clocal_addr.sin_addr, host->h_addr, host->h_length);
  118.         
  119.   bzero (&slocal_addr, ucl);
  120.   slocal_addr.sin_family = AF_INET;
  121.   slocal_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  122.  
  123.   cfd = socket (AF_INET, SOCK_DGRAM, 0);
  124.   bind (cfd, (struct sockaddr *) &clocal_addr, ucl);
  125.  
  126.   sfd = socket (AF_INET, SOCK_DGRAM, 0);
  127.   bind (sfd, (struct sockaddr *) &slocal_addr, ucl);
  128.  
  129.   tvp = NULL;
  130.  
  131.   for (;;)
  132.     {
  133.       int i;
  134.  
  135.       /* this is to exit the spawned processes */
  136.       if (tvp != NULL)
  137.     {
  138.       tv.tv_sec = 15;
  139.       tv.tv_usec = 0;
  140.     }
  141.  
  142.       FD_ZERO (&fds);
  143.       FD_SET (sfd, &fds);
  144.       FD_SET (cfd, &fds);
  145.  
  146.       if (0 >= select (1 + (cfd > sfd ? cfd : sfd), &fds, NULL, NULL, tvp))
  147.     return 0;
  148.  
  149.       /* this should be the 12 byte connect request broadcast */
  150.       if (FD_ISSET (cfd, &fds))
  151.     {
  152.       n = recvfrom (cfd, msg, MAX, 0,
  153.             (struct sockaddr *) &cremote_addr, &ucl);
  154.       if (n == -1)
  155.         {
  156.           perror ("qudproxy");
  157.           return 1;
  158.         }
  159.       if (debug > 1)
  160.         {
  161.           fprintf (stderr, "client@%d: ", ntohs (cremote_addr.sin_port));
  162.           for (i = 0; i < n; ++i)
  163.         fprintf (stderr, "%x ", msg[i]);
  164.           fflush (stderr);
  165.           write (2, "(", 1);
  166.           write (2, msg, n);
  167.           write (2, ")\n", 2);
  168.         }
  169.       sendto (sfd, msg, n, 0, (struct sockaddr *) &sremote_addr, ucl);
  170.     }
  171.  
  172.       if (FD_ISSET (sfd, &fds))
  173.     {
  174.       /* SunOS 4.1.3_U1 requires that we pass in &ucl.  Odd.  */
  175.       n = recvfrom (sfd, msg, MAX, 0, NULL, &ucl);
  176.       if (n == -1)
  177.         {
  178.           perror ("qudproxy");
  179.           return 1;
  180.         }
  181.       if (debug > 1)
  182.         {
  183.           fprintf (stderr, "server@%d: ", ntohs (sremote_addr.sin_port));
  184.           for (i = 0; i < n; ++i)
  185.         fprintf (stderr, "%x ", msg[i]);
  186.           fflush (stderr);
  187.           write (2, "(", 1);
  188.           write (2, msg, n);
  189.           write (2, ")\n", 2);
  190.         }
  191.  
  192.       /* this might be the connect response */
  193.       if (tvp == NULL && msg[0] == 0x80 && msg[1] == 00
  194.           && msg[4] == 0x81)
  195.         {
  196. #if 1
  197.           /* FORK HERE */
  198.           pid = fork ();
  199.           if (!pid)
  200.         {
  201.           /* spawn again */
  202.           if (pid = fork (), pid)
  203.             {
  204.               if (debug)
  205.             fprintf (stderr,
  206.                  "Spawning Quake Proxy Handler Pid %d\n",
  207.                  pid);
  208.               return 0;
  209.               /* if parent, exit (so init gets grandkid) */
  210.             }
  211.         }
  212.           else
  213.         {
  214.           /* wait for kid to exit and continue */
  215.           waitpid (pid, NULL, 0);
  216.           /* create new udp socket for next connections */ 
  217.           close (sfd);
  218.           sfd = socket (AF_INET, SOCK_DGRAM, 0);
  219.           bind (sfd, (struct sockaddr *) &slocal_addr, ucl);
  220.           continue;
  221.         }
  222.           /* we are in grandkid */
  223. #endif
  224.           sremote_addr.sin_port = htons (msg[5] + (msg[6] << 8));
  225.  
  226.           clocal_addr.sin_port = 0;
  227.           c2fd = socket (AF_INET, SOCK_DGRAM, 0);
  228.           bind (c2fd, (struct sockaddr *) &clocal_addr, ucl);
  229.           getsockname (c2fd, (struct sockaddr *) &clocal_addr, &ucl);
  230.           msg[5] = ntohs (clocal_addr.sin_port) & 0xff;
  231.           msg[6] = ntohs (clocal_addr.sin_port) >> 8;
  232.  
  233.           if (debug)
  234.         {
  235.           fprintf (stderr, "Quake UDP Proxy to %s:%d",
  236.                inet_ntoa (sremote_addr.sin_addr),
  237.                ntohs (sremote_addr.sin_port));
  238. #if 0
  239.           /* We haven't asked for this information with
  240.                      getsockname.  */
  241.           fprintf (stderr, " from %s:%d",
  242.                inet_ntoa (slocal_addr.sin_addr),
  243.                ntohs (slocal_addr.sin_port));
  244. #endif
  245.           fprintf (stderr, " for %s:%d",
  246.                inet_ntoa (cremote_addr.sin_addr),
  247.                ntohs (cremote_addr.sin_port));
  248.           fprintf (stderr, " at %s:%d\n",
  249.                inet_ntoa (clocal_addr.sin_addr),
  250.                msg[5] + (msg[6] << 8));
  251.           fflush (stderr);
  252.         }
  253.  
  254.           tvp = &tv;
  255.           sendto (cfd, msg, n, 0, (struct sockaddr *) &cremote_addr, ucl);
  256.           close (cfd);
  257.           cfd = c2fd;
  258.         }
  259.       else
  260.         sendto (cfd, msg, n, 0, (struct sockaddr *) &cremote_addr, ucl);
  261.     }
  262.     }
  263. }
  264.